package com.diaohaiwen.basic.websockt.listener;

import com.diaohaiwen.basic.websockt.obj.vo.WebsocketVo;
import com.diaohaiwen.common.enums.WebsocketEnums;
import com.diaohaiwen.framework.authority.AuthorityUtil;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author 刁海文
 * @Desc 浏览器websocket链接
 */
@Service
@ServerEndpoint("/notice/{token}")
public class WebsocketListener {
    private final Logger logger = LoggerFactory.getLogger("app-websocket");


    /**
     * 计数器
     */
    private final AtomicInteger atomicInteger = new AtomicInteger();

    /**
     * 当前在线session，支持多台设备同时在线
     * key 为用户ID
     */
    public static final Map<String, Set<Session>> ONLINE_USER_SESSIONS = new ConcurrentHashMap<>();

    /**
     * 用户上线
     *
     * @param token   token
     * @param session session
     */
    @OnOpen
    public void online(@PathParam("token") String token, Session session) throws IOException {

        String userId = AuthorityUtil.getLoginId(token);

        WebsocketVo<Object> message = WebsocketVo.build(WebsocketEnums.LOGIN, userId);

        broadcast(message);
        if (!ONLINE_USER_SESSIONS.containsKey(userId)) {
            ONLINE_USER_SESSIONS.put(userId, new HashSet<>());
            atomicInteger.incrementAndGet();
        }
        ONLINE_USER_SESSIONS.get(userId).add(session);
        logger.info("用户：{}，ID：{}上线，当前在线设备数量{}", AuthorityUtil.getUserName(userId), userId, ONLINE_USER_SESSIONS.get(userId).size());

    }

    /**
     * 用户下线
     *
     * @param token   用户ID
     * @param session session
     */
    @OnClose
    public void offline(@PathParam("token") String token, Session session) {
        String userId = AuthorityUtil.getLoginId(token);
        ONLINE_USER_SESSIONS.get(userId).remove(session);
        if (ONLINE_USER_SESSIONS.get(userId).isEmpty()) {
            atomicInteger.decrementAndGet();
            ONLINE_USER_SESSIONS.remove(userId);
        }
        logger.info("用户：{}，ID：{}下线，当前在线设备数量{}", AuthorityUtil.getUserName(userId), userId, ONLINE_USER_SESSIONS.getOrDefault(userId, new HashSet<>()).size());
        WebsocketVo<Object> message = WebsocketVo.build(WebsocketEnums.LOGIN, userId);

        Set<String> userIds = ONLINE_USER_SESSIONS.keySet();
        userIds.remove(userId);
        sendMessage(message, userIds);

    }


    /**
     * 收到客户端消息后调用
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("token") String token) {
        String userId = AuthorityUtil.getLoginId(token);
        logger.info("收到客户端 {} 消息：{}", userId, message);
    }

    /**
     * 发生错误/异常时调用
     */
    @OnError
    public void onError(Session session, Throwable error, @PathParam("token") String token) {
        String userId = AuthorityUtil.getLoginId(token);
    }

    /**
     * 指定Session发送消息
     *
     * @param userId  用户ID
     * @param message 发送的消息
     */
    public static boolean sendMessage(String message, String userId) {
        if (!ONLINE_USER_SESSIONS.containsKey(userId)) {
            return false;
        }
        for (Session session : ONLINE_USER_SESSIONS.get(userId)) {
            session.getAsyncRemote().sendText(message);
        }
        return true;
    }

    /**
     * 群发指定Session发送消息
     *
     * @param userIds  需要发送的用户id
     * @param messages 发送的消息
     */
    public static <T> void sendMessage(WebsocketVo<T> messages, String... userIds) {
        if (userIds == null) {
            return;
        }
        String message = messages.toString();
        for (String userId : userIds) {
            sendMessage(message, userId);
        }
    }

    /**
     * 群发指定Session发送消息
     *
     * @param userIds 需要发送的用户id
     */
    public static <T> void sendMessage(WebsocketVo<T> messages, Collection<String> userIds) {
        if (userIds == null) {
            return;
        }
        String message = messages.toString();
        for (String userId : userIds) {
            sendMessage(message, userId);
        }
    }

    public static <T> void broadcast(WebsocketVo<T> message) {
        sendMessage(message, ONLINE_USER_SESSIONS.keySet());
    }

}
